import database as db
from twisted.python import log
import commands
from update_logic import locking, check_update
from collections import namedtuple

Request = namedtuple('Request', 'loc_id, type info source target target_cell cost')

# request functions to perform an action
requests = {}

def req(func):
    requests[func.func_name.upper()] = func
    return func

def create_request(loc_id, type, source, info = '', target = None,
                   target_cell = None, cost = 20):
    
    r = Request(loc_id, type, info, source,
              target, target_cell, cost)
    
    db.Location._requests[loc_id].append(r)
    
########### SYSTEM REQUESTS: ###########    

def ENTER(player, loc_id, (x,y) = (None,None)):
    ''' Places character at designated location or if not specified: any free safe location '''
    
    if not player.creature:
        raise Exception, "No creature for player"+str(player)
    player.loc_id = loc_id
    @locking("system", id = loc_id)
    def add(lock):
        with db.Handler(True) as h:
            if x == None or y == None:
                targ_cell = None
            else:
                targ_cell = h.session.query(db.Cell)\
                .filter_by(loc_id = loc_id)\
                .filter_by(coords = (x,y)).one()
            create_request(loc_id, 'enter', player.creature, target_cell=targ_cell)
        player.committed = True
        check_update(player)
    
def EXIT(player):
    ''' removes creature from location '''
    # TODO:
 

########### REQUESTS: ###########    

@req
def MOVE(player, info):
    ''' Moves character in direction '''
    assert player.loc_id, "Player has no location yet"
    with db.Handler(True) as h:
        
        @locking("move", id = player.loc_id)
        def move(lock):
            cre = player.creature
            h.session.add(cre)
            if not cre.cell:
                player.send(commands.error("You have not yet entered the game"))
                return
            
            if not info:
                player.send(commands.error("No direction given for 'move'"))
                return
            
            if not set(info.lower()) <= set('nswe'):
                player.send(commands.error("unknown direction given: "+info))
                return
            create_request(player.loc_id, "move", player.creature, info, cost=20)
    

@req
def COMMIT(player):
    if not player.loc_id:
        raise Exception("Player is not yet in any location to commit")
    
    @locking("commit", toThread=False, id=player.loc_id)
    def upd(lock):
        player.committed = True
        check_update(player)

@req
def CANCEL(player, n = None):
    ''' cancells n actions '''

@req
def ATTACK(player, target):
    if not player.loc_id:
        player.send(commands.error("player have no loc_id"))
        return
    @locking("attack", id = player.loc_id)
    def attack(lock):
        with db.Handler(True) as h:
            cre = player.creature
            h.session.add(cre)
            if not cre.cell:
                player.send(commands.error("You have not yet entered the game"))
                return  
            target_c = cre.location.strid_objects[target]      
            # TODO: request
            